/*
    YmsgIRC - Program enabling YMSG chat clients to use IRC
    Copyright (C) 2011 Crash Daemonicus ( crashenator -at- gmail.com )

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/



#include "YMSG_fieldparser.h"


YmsgObject::YmsgObject(const YmsgField& f){type=YMSG_FIELD; field=f;}
YmsgObject::YmsgObject(const YmsgList & l){type=YMSG_LIST ; list =l;}
YmsgObject::YmsgObject(const YmsgItem & i){type=YMSG_ITEM ; item =i;}


//----------------------------------------------------------------------------------

vector<YmsgObject> YmsgFieldParser::filterObjects(const vector<YmsgObject>& objects, YmsgObjectType type, bool include)
{
	bool match;
	vector<YmsgObject> included;
	foreach_vector_const(YmsgObject,it,objects)
	{
		match=type == (*it).type;
		if(match==include) included.push_back(*it);// match AND include-matches = included     no-match AND exclude-matches=included 
	}
	return included;
}
vector<YmsgItem> YmsgFieldParser::filterItemObjects(const vector<YmsgObject>& objects)
{
	vector<YmsgItem> included;
	foreach_vector_const(YmsgObject,it,objects) if((it->type)==YMSG_ITEM) included.push_back(it->item);
	return included;
}


vector<YmsgField> YmsgFieldParser::getFields(const string& data){
	vector<YmsgField> fields;
	vector<string> parts;
	StringExplode(data,parts,YMSG_DELIMITER);

	bool isId=true;
	int id;
	foreach_vector(string,it,parts)
	{
		//printf("\n Part {%d} = {%s}\n", 
		if(isId) id=stoi(*it);
		else{//contents come right after the id, completing the field
			fields.push_back(YmsgField(id,*it));
		}
		isId=!isId;//alternate on/off
	}
	return fields;
}


vector<YmsgObject> YmsgFieldParser::getObjects(const vector<YmsgField>& fields)
{
	vector<YmsgObject> objects;

	vector<YmsgField> content;
	bool started=false;
	int idSearch=0;
	string valSearch="";
	foreach_vector_const(YmsgField,it,fields)
	{
		const YmsgField& field=*it;

		switch(field.num)
		{
			case YMSG_FIELD_ITEMBEGIN:
			case YMSG_FIELD_LISTBEGIN:
				if(!started){ idSearch=field.num+1; valSearch=field.value; started=true; }//search for Item/List End with same value  (YMSG_FIELD_?END==?BEGIN+1)
				else content.push_back(field);
				break;
			case YMSG_FIELD_ITEMEND:
			case YMSG_FIELD_LISTEND:
			{
				if(started && field.num==idSearch && field.value==valSearch)
				{//completed list/item
					if(field.num==YMSG_FIELD_ITEMEND) objects.push_back(YmsgItem(stoi(field.value),content));
					else{// LIST
						objects.push_back(
							YmsgList(
								stoi(field.value), 
								filterItemObjects(getObjects(content))
							)
						);
					}//end List check
					started=false;
					content.clear();//reset the gathered content for the next YmsgObject
				}else if(started) {//list/item search started, but this isn't the completing field
					content.push_back(field);
				}else {//list/item end in the middle of nowhere without a beginning!
					objects.push_back(YmsgObject(field));
				}
				break;
			}//end List/Item check
			default:
				if(started) content.push_back(field);
				else objects.push_back(YmsgObject(field));
		}//end switch
	}//end for loop
	return objects;
}
vector<YmsgObject> YmsgFieldParser::getObjects(const string& data){return getObjects(getFields(data));}

vector<YmsgObject> YmsgFieldParser::getObjects(const vector<YmsgItem>& items)
{
	vector<YmsgObject> objects;
	foreach_vector_const(YmsgItem,it,items) objects.push_back( YmsgObject(*it) );
	return objects;
}
vector<YmsgObject> YmsgFieldParser::getObjects(const vector<YmsgList>& lists)
{
	vector<YmsgObject> objects;
	foreach_vector_const(YmsgList,it,lists) objects.push_back( YmsgObject(*it) );
	return objects;
}




void YmsgFieldParser::debugObjects(const vector<YmsgObject>& objects)
{
	foreach_vector_const(YmsgObject,it,objects)
	{
		switch(it->type)
		{
			case YMSG_FIELD:
				dbgline("Field ");dbg(it->field.str.c_str());
				break;
			case YMSG_ITEM:
			{
				char disp[255];
				sprintf(disp,"Item  %d",it->item.type);
				dbg_head(disp);
				debugObjects(getObjects(it->item.fields));
				dbg_foot(0);
				break;
			}
			case YMSG_LIST:
			{
				char disp[255];
				sprintf(disp,"List  %d",it->list.type);
				dbg_head(disp);
				debugObjects(getObjects(it->list.items));
				dbg_foot(0);
			}
		}//switch
	}//for
}//func
/*




vector<YmsgField> YmsgFieldParser::getFieldRange(const vector<YmsgField>& fields, int startID, int endID, string& sType, int occur=1)
{
	bool started=false;
	int ioccur=0;
	vector<YmsgField> content;


	foreach_vector_const(YmsgField,it,fields)
	{
		const YmsgField& field=*it;


		bool match_type=(field.value==sType || sType=="");
		bool match_begin=  num==startID && !started && match_type;
		bool match_end  =  num==  endID &&  started && match_type;

		if(match_begin)
		{
			ioccur++;
			match_begin=(ioccur==occur);//if it matches the search parameters, does it also match the occurence number?
		}


		if(match_begin){//the item has begun.
			sType=field.value;//if type==0
			started=true;
		}else if(match_end){//the item has ended.
			//finished
			return content
		}else if(started){//the item has been started, but this field is not a Item-marker field; it is in the Item body
			content.push_back(*it);
		}
	}
	content.clear();
	return content;
}

YmsgItem YmsgFieldParser::getItem(const vector<YmsgField>& fields, string sType, int occur=1)
{
	vector<YmsgField> content=getFieldRange(fields,YMSG_FIELD_ITEMBEGIN,YMSG_FIELD_ITEMEND,sType,occur);
	return YmsgItem(stoi(sType),content);
}
YmsgList YmsgFieldParser::getList(const vector<YmsgField>& fields, string sType, int occur=1)
{
	vector<YmsgField> content=getFieldRange(fields,YMSG_FIELD_LISTBEGIN,YMSG_FIELD_LISTEND,sType,occur);
	YmsgItem item();
	do{
		item=getItem(fields,sType
	}while();
	
}

int YMSG::debugFields(const vector<YmsgField>& fields, )
{
	vector<YmsgField>::const_iterator it_item;
	vector<YmsgField>::const_iterator it_list;
	foreach_vector_const(YmsgField,it,fields)
	{
		int num=(*it).num
		string val=(*it).value
		switch(num)
		{
			case YMSG_FIELD_LISTBEGIN:
			{
				dbg_head("YmsgList");
				dbg_foot(0);
				break;
			}
			case YMSG_FIELD_ITEMBEGIN:
			{
				dbg_head("YmsgItem");
				dbg_foot(0);
				break;
			}
			default:
				dbgline("Field ");dbg(itos(num).c_str());dbg("=");dbg(val.c_str());
		}
		if((*it).num==YMSG_FIELD_LISTBEGIN)
	}
}
*/